home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / contrib / sblaster / sb.c < prev    next >
C/C++ Source or Header  |  1993-11-16  |  11KB  |  552 lines

  1. /*
  2.  * Play digitized sound sample on soundblaster DAC using DMA.
  3.  * This source code is in the public domain.
  4.  * 
  5.  * Modification History
  6.  *
  7.  *  9-Nov-93    David Baggett        Wrote it based on Sound Blaster
  8.  *        <dmb@ai.mit.edu>    Freedom project and Linux code.
  9.  *
  10.  */
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <stdio.h>
  14. #include <go32.h>
  15. #include <dos.h>
  16. #include <dpmi.h>
  17. #include <string.h>
  18. #include <pc.h>
  19.  
  20. #include "sb.h"
  21.  
  22. #define _PROTO_(x) x
  23.  
  24. #include "proto.h"
  25.  
  26. /*
  27.  * Define TEST to make an executable (i.e., compile main).
  28.  */
  29. #define TEST
  30.  
  31. /*
  32.  * GO32 DPMI structs for accessing DOS memory.
  33.  */
  34. static _go32_dpmi_seginfo dosmem;    /* DOS (conventional) memory buffer */
  35.  
  36. static _go32_dpmi_seginfo oldirq_rm;    /* original real mode IRQ */
  37. static _go32_dpmi_registers rm_regs;
  38. static _go32_dpmi_seginfo rm_si;    /* real mode interrupt segment info */
  39.  
  40. static _go32_dpmi_seginfo oldirq_pm;    /* original prot-mode IRQ */
  41. static _go32_dpmi_seginfo pm_si;    /* prot-mode interrupt segment info */
  42.  
  43. /*
  44.  * Card parameters
  45.  */
  46. static unsigned int    sb_ioaddr;
  47. static unsigned int    sb_irq;
  48. static unsigned int    sb_dmachan;
  49.  
  50. /*
  51.  * Is a sound currently playing?
  52.  */
  53. static volatile int    sb_sound_playing = 0;
  54.  
  55. /*
  56.  * Conventional memory buffers for DMA.
  57.  */
  58. static volatile int    sb_bufnum = 0;
  59. static char        *sb_buf[2];
  60. static unsigned int    sb_buflen[2];
  61.  
  62. /*
  63.  * Info about current sample
  64.  */
  65. static unsigned char    *sb_curdata;    /* pointer to next bit of data */
  66. static unsigned long    sb_curlength;    /* total length length left to play */
  67.  
  68. /*
  69.  * DMA chunk size, in bytes.
  70.  *
  71.  * This parameter determines how big our DMA buffers are.  We play
  72.  * the sample by piecing together chunks that are this big.  This
  73.  * means that we don't have to copy the entire sample down into
  74.  * conventional memory before playing it.  (A nice side effect of
  75.  * this is that we can play samples that are longer than 64K.)
  76.  *
  77.  * Setting this is tricky.  If it's too small, we'll get lots
  78.  * of interrupts, and slower machines might not be able to keep
  79.  * up.  Furthermore, the smaller this is, the more grainy the
  80.  * sound will come out.
  81.  *
  82.  * On the other hand, if we make it too big there will be a noticeable
  83.  * delay between a call to sb_play and when the sound actually starts
  84.  * playing, which is unacceptable for things like games where sound
  85.  * effects should be "instantaneous".
  86.  *
  87.  */
  88. #define DMA_CHUNK (2048)
  89.  
  90. /*
  91.  * Define replacements for DOS enable and disable.
  92.  * Be careful about inlining these -- GCC has a tendency to move
  93.  * them around even if you declare them volatile.  (This is definitely
  94.  * true before 2.5.2; may be fixed in 2.5.2.)
  95.  */
  96. void
  97. disable()
  98. {
  99.     __asm__ __volatile__ ("cli");
  100. }
  101. void
  102. enable()
  103. {
  104.     __asm__ __volatile__ ("sti");
  105. }
  106.  
  107. /*
  108.  * Interrupt handler
  109.  *
  110.  * This is called in both protected mode and in real mode -- this means
  111.  * we don't have to switch modes when we service the interrupt.
  112.  */
  113. void
  114. sb_intr(_go32_dpmi_registers *reg)
  115. {
  116.     register unsigned n = sb_bufnum;    /* buffer we just played */
  117.  
  118.     /*
  119.      * Acknowledge soundblaster
  120.      */
  121.     inportb(sb_ioaddr + SB_DSP_DATA_AVAIL);
  122.  
  123.     /*
  124.      * Start next buffer player
  125.      */
  126.     sb_play_buffer(1 - n);
  127.     
  128.     /*
  129.      * Fill this buffer for next time around
  130.      */
  131.     sb_fill_buffer(n);
  132.     
  133.     /*
  134.      * Acknowledge the interrupt
  135.      */
  136.     outportb(0x20, 0x20);
  137.  
  138.     enable();
  139. }
  140.  
  141. /*
  142.  * Fill buffer n with the next data.
  143.  */
  144. void
  145. sb_fill_buffer(register unsigned n)
  146. {
  147.     if (sb_curlength > DMA_CHUNK) {
  148.         sb_buflen[n] = DMA_CHUNK;
  149.         dosmemput(sb_curdata, DMA_CHUNK, (unsigned long) sb_buf[n]);
  150.         sb_curlength -= DMA_CHUNK;
  151.         sb_curdata += DMA_CHUNK;
  152.     }
  153.     else if (sb_curlength == 0) {
  154.         sb_buflen[n] = 0;
  155.         sb_curlength = 0;
  156.     }
  157.     else {
  158.         sb_buflen[n] = sb_curlength;
  159.         dosmemput(sb_curdata, sb_curlength, (unsigned long) sb_buf[n]);
  160.         sb_curdata += sb_curlength;
  161.         sb_curlength = 0;
  162.     }
  163. }
  164.  
  165. void
  166. sb_play_buffer(register unsigned n)
  167. {
  168.     int        t;
  169.     unsigned char    im, tm;
  170.  
  171.     /*
  172.      * See if we're already done
  173.      */
  174.     if (sb_buflen[n] == 0) {
  175.         sb_sound_playing = 0;
  176.         return;
  177.     }
  178.     
  179.     disable();
  180.  
  181.     /*
  182.      * Enable interrupts on PIC
  183.      */
  184.     im = inportb(0x21);
  185.     tm = ~(1 << sb_irq);
  186.     outportb(0x21,im & tm);
  187.  
  188.     /*
  189.      * Set DMA mode
  190.      */
  191.     outportb(SB_DMA_MASK, 5);
  192.     outportb(SB_DMA_FF, 0);
  193.     outportb(SB_DMA_MODE, 0x49);
  194.     
  195.     /*
  196.      * Set transfer address
  197.      */
  198.     sb_bufnum = n;
  199.     t = (int) ((unsigned long) sb_buf[n] >> 16);
  200.     outportb(SB_DMAPAGE + 3, t);
  201.     t = (int) ((unsigned long) sb_buf[n] & 0xFFFF);
  202.     outportb(SB_DMA + 2 * sb_dmachan, t & 0xFF);
  203.     outportb(SB_DMA + 2 * sb_dmachan, t >> 8);
  204.  
  205.     /*
  206.      * Set transfer length byte count
  207.      */
  208.     outportb(SB_DMA + 2 * sb_dmachan + 1, sb_buflen[n] & 0xFF);
  209.     outportb(SB_DMA + 2 * sb_dmachan + 1, sb_buflen[n] >> 8);
  210.  
  211.     /*
  212.      * Unmask DMA channel
  213.      */
  214.     outportb(SB_DMA_MASK, sb_dmachan);
  215.  
  216.     enable();
  217.  
  218.     sb_writedac(SB_DMA_8_BIT_DAC); /* command byte for DMA DAC transfer */
  219.  
  220.     /* sb_write length */
  221.     sb_writedac(sb_buflen[n] & 0xFF);
  222.     sb_writedac(sb_buflen[n] >> 8);
  223.  
  224.     /*
  225.      * A sound is playing now.
  226.      */
  227.     sb_sound_playing = 1;
  228. }
  229.  
  230. /*
  231.  * Set sampling/playback rate.
  232.  * Parameter is rate in Hz (samples per second).
  233.  */
  234. void
  235. sb_set_sample_rate(unsigned int rate)
  236. {
  237.     unsigned char tc = (unsigned char) (256 - 1000000/rate);
  238.  
  239.     sb_writedac(SB_TIME_CONSTANT);    /* Command byte for sample rate */
  240.     sb_writedac(tc);        /* Sample rate time constant */
  241. }
  242.  
  243. void
  244. sb_voice(int state)
  245. {
  246.     sb_writedac(state ? SB_SPEAKER_ON : SB_SPEAKER_OFF);
  247. }
  248.  
  249. /*
  250.  * Read soundblaster card parameters from BLASTER enivronment variable.
  251.  */
  252. void
  253. sb_getparams()
  254. {
  255.     char *t, *blaster;
  256.  
  257.     /*
  258.      * Set arguments to Soundblaster defaults
  259.      */
  260.     sb_ioaddr = 0x220;
  261.     sb_irq = 7;
  262.     sb_dmachan = 1;
  263.  
  264.     t = getenv("BLASTER");
  265.     if (!t)
  266.         return;
  267.  
  268.     /*
  269.      * Get a copy
  270.      */
  271.     blaster = strdup(t);
  272.  
  273.     /*
  274.      * Parse the BLASTER variable
  275.      */
  276.     t = strtok(blaster, " \t");
  277.     while (t) {
  278.         switch (t[0]) {
  279.             case 'A':
  280.             case 'a':
  281.                 /* I/O address */
  282.                 sscanf(t + 1, "%x", &sb_ioaddr);
  283.                 break;
  284.             case 'I':
  285.             case 'i':
  286.                 /* IRQ */
  287.                 sb_irq = atoi(t + 1);
  288.                 break;
  289.             case 'D':
  290.             case 'd':
  291.                 /* DMA channel */
  292.                 sb_dmachan = atoi(t + 1);
  293.                 break;
  294.             case 'T':
  295.             case 't':
  296.                 /* what is this? */
  297.                 break;
  298.                 
  299.             default:
  300.                 printf("Unknown BLASTER option %c\n",t[0]);
  301.                 break;
  302.         }
  303.         t = strtok(NULL," \t");
  304.     }
  305.  
  306.     free(blaster);    
  307.     return;
  308. }
  309.  
  310. /*
  311.  * Init the soundblaster card.
  312.  */
  313. void
  314. sb_initcard()
  315. {
  316.     outportb(sb_ioaddr + SB_DSP_RESET, 1);
  317.     
  318.     /*
  319.      * Kill some time
  320.      */
  321.     inportb(sb_ioaddr + SB_DSP_RESET);
  322.     inportb(sb_ioaddr + SB_DSP_RESET);
  323.     inportb(sb_ioaddr + SB_DSP_RESET);
  324.     inportb(sb_ioaddr + SB_DSP_RESET);
  325.     
  326.     outportb(sb_ioaddr + SB_DSP_RESET, 0);
  327.     
  328.     /*
  329.      * Need to add a timeout here!
  330.      */
  331.     while (inportb(sb_ioaddr + SB_DSP_READ_DATA) != 0xAA)
  332.         ;    
  333. }
  334.  
  335. /*
  336.  * Install our interrupt as the real mode interrupt handler for 
  337.  * the IRQ the soundblaster is on.
  338.  *
  339.  * We accomplish this by have GO32 allocate a real mode callback for us.
  340.  * The callback packages our protected mode code up in a real mode wrapper.
  341.  */
  342. void
  343. sb_install_rm_interrupt()
  344. {
  345.     int    ret;
  346.  
  347.     rm_si.pm_offset = (int) sb_intr;
  348.     ret = _go32_dpmi_allocate_real_mode_callback_iret(&rm_si, &rm_regs);
  349.     if (ret != 0) {
  350.         printf("cannot allocate real mode callback, error=%04x\n",ret);
  351.         exit(1);
  352.     }
  353.  
  354. #ifdef    TEST
  355.     printf("real mode callback is at %04x:%04x\n",
  356.            rm_si.rm_segment, rm_si.rm_offset);
  357. #endif
  358.  
  359.     /*
  360.      * Install our real mode interrupt handler
  361.      */
  362.     disable();
  363.     _go32_dpmi_get_real_mode_interrupt_vector(8 + sb_irq, &oldirq_rm);
  364.     _go32_dpmi_set_real_mode_interrupt_vector(8 + sb_irq, &rm_si);
  365.     enable();
  366. }
  367.  
  368. /*
  369.  * Remove our real mode interrupt handler.
  370.  */
  371. void
  372. sb_cleanup_rm_interrupt()
  373. {
  374.     disable();
  375.     _go32_dpmi_set_real_mode_interrupt_vector(8 + sb_irq, &oldirq_rm);
  376.     _go32_dpmi_free_real_mode_callback(&rm_si);
  377.     enable();
  378. }
  379.  
  380. /*
  381.  * Install our interrupt as the protected mode interrupt handler for 
  382.  * the IRQ the soundblaster is on.
  383.  */
  384. void
  385. sb_install_pm_interrupt()
  386. {
  387.     disable();
  388.     _go32_dpmi_get_protected_mode_interrupt_vector(8 + sb_irq, &oldirq_pm);
  389.     pm_si.pm_offset = (int) sb_intr;
  390.     pm_si.pm_selector = _go32_my_cs();
  391.     _go32_dpmi_chain_protected_mode_interrupt_vector(8 + sb_irq, &pm_si);
  392.     enable();
  393. }
  394.  
  395. /*
  396.  * Remove our protected mode interrupt handler.
  397.  */
  398. void
  399. sb_cleanup_pm_interrupt()
  400. {
  401.     disable();
  402.     _go32_dpmi_set_protected_mode_interrupt_vector(8 + sb_irq, &oldirq_pm);
  403.     enable();
  404. }
  405.  
  406. /*
  407.  * Allocate conventional memory for our DMA buffers.
  408.  * Each DMA buffer must be aligned on a 64K boundary in physical memory.
  409.  */
  410. void
  411. sb_init_buffers()
  412. {
  413.     dosmem.size = 65536*3/16;
  414.     if (_go32_dpmi_allocate_dos_memory(&dosmem)) {
  415.         printf("Unable to allocate dos memory - max size is %d\n", dosmem.size);
  416.         exit(1);
  417.     }
  418.  
  419. #ifdef    TEST
  420.     printf("dos buffer at 0x%04x:0\n", dosmem.rm_segment);
  421. #endif
  422.     
  423.     (unsigned long) sb_buf[0] = dosmem.rm_segment * 16;
  424.     (unsigned long) sb_buf[0] += 0x0FFFFL;
  425.     (unsigned long) sb_buf[0] &= 0xFFFF0000L;
  426.     (unsigned long) sb_buf[1] = (unsigned long) sb_buf[0] + 0x10000;
  427.     
  428. #ifdef    TEST
  429.     printf("DMA buffers at physical 0x%0x and 0x%0x\n",
  430.            (unsigned int) sb_buf[0], (unsigned int) sb_buf[1]);
  431. #endif
  432. }
  433.  
  434. /*
  435.  * Initliaze our internal buffers and the card itself to prepare
  436.  * for sample playing.
  437.  *
  438.  * Call this once per program, not once per sample.
  439.  */
  440. void 
  441. sb_init()
  442. {
  443.     /*
  444.      * Card card params and initialize card.
  445.      */
  446.     sb_getparams();
  447.     sb_initcard();
  448.     
  449.     /*
  450.      * Install our interrupt handlers
  451.      */
  452.     sb_install_rm_interrupt();
  453.     sb_install_pm_interrupt();
  454.     
  455.     /*
  456.      * Allocate buffers in conventional memory for double-buffering
  457.      */
  458.     sb_init_buffers();
  459. }
  460.  
  461. /*
  462.  * Restore card and system to sane state before exiting.
  463.  */
  464. void
  465. sb_cleanup()
  466. {
  467.     /*
  468.      * Remove our interrupt handlers
  469.      */
  470.     sb_cleanup_rm_interrupt();
  471.     sb_cleanup_pm_interrupt();
  472. }
  473.  
  474. /*
  475.  * Play a sample through the DAC using DMA.
  476.  */
  477. void
  478. sb_play(unsigned char *data, unsigned long length)
  479. {
  480.     /*
  481.      * Prime the buffers
  482.      */
  483.     sb_curdata = data;
  484.     sb_curlength = length;
  485.     sb_fill_buffer(0);
  486.     sb_fill_buffer(1);
  487.     
  488.     /*
  489.      * Start the first buffer playing.
  490.      */
  491.     sb_play_buffer(0);
  492. }
  493.  
  494. #ifdef    TEST
  495. void
  496. main(argc, argv)
  497.     int    argc;
  498.     char    **argv;
  499. {
  500.     unsigned long    length;
  501.     unsigned char    *data;
  502.     FILE        *fp;
  503.     struct stat    statbuf;
  504.  
  505.     if (argc < 3) {
  506.         printf("usage: sb sample.sam sample-rate\n");
  507.         printf("sample-rate is in hertz (e.g., 11000)\n");
  508.         exit(0);
  509.     }
  510.  
  511.     if (stat(argv[1], &statbuf) < 0) {
  512.         printf("%s: can't stat %s\n", argv[0], argv[1]);
  513.         exit(1);
  514.     }
  515.     
  516.     length = statbuf.st_size;
  517.     
  518.     data = calloc(length, 1);
  519.     if (!data) {
  520.         printf("%s: out of memory\n", argv[0]);
  521.         exit(1);
  522.     }
  523.     
  524.     fp = fopen(argv[1], "rb");
  525.     if (!fp) {
  526.         printf("%s: can't open %s\n", argv[0], argv[1]);
  527.         exit(1);
  528.     }
  529.     
  530.     if (fread(data, 1, length, fp) < length) {
  531.         printf("%s: error reading %s\n", argv[0], argv[1]);
  532.         exit(1);
  533.     }
  534.     
  535.     sb_init();
  536.         
  537.     printf("I/O addr = %x, IRQ = %d, DMA channel = %d\n",
  538.            sb_ioaddr, sb_irq, sb_dmachan);
  539.     
  540.     sb_voice(1);
  541.     sb_set_sample_rate(atoi(argv[2]));
  542.     sb_play(data, length);
  543.     
  544.     while (sb_sound_playing)
  545.         ;
  546.  
  547.     sb_cleanup();
  548.     
  549.     exit(0);
  550. }
  551. #endif
  552.